package com.zjmcollege.hotpot.component;

import com.zjmcollege.hotpot.config.Config;
import com.zjmcollege.hotpot.enums.FileType;
import com.zjmcollege.hotpot.exception.ServerException;
import com.zjmcollege.hotpot.exception.UploadFileIsEmpty;
import com.zjmcollege.hotpot.model.UploadResultModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.UUID;

/**
 * @author zpym
 * @CopyRight (C) http://www.iengoo.com
 * @brief
 * @email 122162005@qq.com
 * @date 2019-11-19 17:08
 */
@Component
@Slf4j
public class FileHandler {
    @Autowired
    private Config config;

    /**
     * 上传文件：根据文件类型，将文件写入到不同的文件夹中
     *
     * @param file
     * @param fileType 文件类型
     * @return
     */
    public UploadResultModel upload(MultipartFile file, FileType fileType) {
        UploadResultModel result = new UploadResultModel();
        if (file.isEmpty()) {
            log.info("文件为空");
            throw new UploadFileIsEmpty();
        }

        String originalName = file.getOriginalFilename();  // 文件名
        String suffixName = originalName.substring(originalName.lastIndexOf("."));  // 后缀名
        String filePath = config .getFilePath();
        switch (fileType) {
            case IMAGE:
                filePath += "images\\"; // 上传后的路径
                break;
            case ATTACH:
                filePath += config.getAttachUriPattern() + "\\"; // 上传后的路径
                break;
        }
        // 重新定义文件名字
        String newName = UUID.randomUUID().toString().replaceAll("-", "") + suffixName; // 新文件名

        File dest = new File(filePath + newName);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getLocalizedMessage());
            throw new ServerException();
        }

        String filename = null;
        switch (fileType) {
            case IMAGE :
                filename = "/img/" + newName;
                break;
            case ATTACH:
                filename = "/" + config.getAttachUriPattern() + "/" + newName;
                break;
        }

        result.setOriginal(originalName);
        result.setUrl(filename);
        result.setFilename(newName);
        return result;
    }

    /**
     * https://www.jianshu.com/p/a1f37bcbdf9f
     * https://www.jianshu.com/p/de36bd53f11f
     * https://www.jianshu.com/p/90cbac3b47f0
     * https://www.jianshu.com/p/60913b2b7f45
     * @param doc
     * @param fileType
     * @return
     */
    public UploadResultModel upload(String doc, FileType fileType) {
        UploadResultModel result = new UploadResultModel();
        if (doc.isEmpty()) {
            log.info("文件为空");
            throw new UploadFileIsEmpty();
        }
        String filePath = config .getFilePath();
        // 重新定义文件名字
        String newName = null;
        String uri = null;

        switch (fileType) {
            case MD:
                filePath += config.getMdUriPattern() + "\\"; // 上传后的路径
                newName = UUID.randomUUID().toString().replaceAll("-", "") + ".md"; // 新文件名
                uri = "/" + config.getMdUriPattern() + "/" + newName;
                break;
            case HTML:
                filePath += config.getHtmlUriPattern() + "\\"; // 上传后的路径
                newName = UUID.randomUUID().toString().replaceAll("-", "") + ".html"; // 新文件名
                uri = "/" + config.getHtmlUriPattern() + "/" + newName;
                break;
        }

        File dest = new File(filePath + newName);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try (FileOutputStream outputStream = new FileOutputStream(dest);
             FileChannel channel = outputStream.getChannel()){

            ByteBuffer docBytes = ByteBuffer.wrap(doc.getBytes("UTF-8"));
            channel.write(docBytes);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getLocalizedMessage());
            throw new ServerException();
        }

        result.setOriginal(newName);
        result.setUrl(uri);
        result.setFilename(newName);
        return result;
    }

    /**
     * 根据 文件的 uri 获取文件中的文件内容
     * @param uri
     * @return
     */
    public String getContent(String uri, FileType type) {
        // 通过 uri 获取文件名
        String filename = uri.substring(uri.lastIndexOf("/") + 1);
        String path = config.getFilePath();
        switch (type) {
            case MD:
                path += config.getMdUriPattern() + "/" + filename;
                break;
            case HTML:
                path += config.getHtmlUriPattern() + "/" + filename;
                break;
        }

        return reader(path);
    }

    private String reader(String path) {
        try (RandomAccessFile raf = new RandomAccessFile (path, "rw");
             FileChannel channel = raf.getChannel()
        ){
            ByteBuffer bb = ByteBuffer.allocate((int)raf.length());
            channel.read(bb);
            // 将缓冲中的数据强制刷到bb中
            bb.flip();
            CharBuffer cb = CharBuffer.allocate((int)raf.length());
            Charset.forName("utf-8").newDecoder().decode(bb, cb, true);
            cb.flip();

            return cb.toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error("文件不存在");
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            log.error("处理文件失败");
            return null;
        }
    }
}
